#include "AzField.h"

const char FIELDS_TAG[] = "FIELDS";
const char FIELD_TAG[] = "FIELD";
const char VERSION_ATTR[] = "Version";

#include <QMetaProperty>

#include "AzRootRecord.h"

#include "Az.h"
/*!
	\class AzField
	Class constaints metadata for field
	\Warning Property name() must be first, property type() must be second
*/

/*!
	fkData - тип поля дата
	fkCalc - вычисляемое поле
*/

//-------------------------------------------------------AzFieldException------------------------------------------


AzFieldException::AzFieldException(Error err) : AzException() {
   mErrCode = err;
   mMessage = codeToStr(err);
}


QString AzFieldException::codeToStr(Error err) {
    switch (err) {
    case CannotChangeFieldError:          return "Has a data, cannot change field metadata";
    case InvalidFieldTypeError:           return "Field must have a valid type";
    default: break;
    }
    return QString();
}

AzField::AzField() :QObject(0), mLenght(-1),mFieldKind(DataFieldKind) {
}

AzField::AzField(const AzField& src):QObject(0) {
    copy(src);
}

AzField& AzField::operator = (const AzField& src) {
    if (this == &src)
        return *this;
    copy(src);
    return *this;
}

void AzField::copy(const AzField& src) {
    mName = src.mName;
    mType = src.mType;
    mDisplayName = src.mDisplayName;
    mLenght = src.mLenght;
    mFieldKind = src.mFieldKind;
}

/*!
 * \brief AzField::~AzField
 * Destroy field and remote it from AzFieldList (if assign)
 */
AzField::~AzField() {
}




void AzField::writeXml(QXmlStreamWriter& stream) const {
	stream.writeStartElement(FIELD_TAG);
	const QMetaObject *meta = metaObject();
	for (int i = meta->propertyOffset(); i < meta->propertyCount(); ++i) {
		QMetaProperty prop = meta->property(i);
		stream.writeAttribute(prop.name(), prop.read(this).toString());
	}
	stream.writeEndElement();
}


/*-----------------------------------------------------------------AzFieldList-------------------------------------------*/
/*!
    \class AzFieldList о
    Содержит список полей.
    Важный вопрос в реализации. Список полей должен совпадать со списком данных (размер и тип) корневой записи.
    Есть 2 пути - либо полностью независимый класс, с событиями, либо прямая зависимость. Выбран второй путь.
*/


AzFieldList::AzFieldList(QObject* parent):QObject(parent),mRootRec(0) {
}

AzFieldList::AzFieldList(const AzRootRecord* rec):mRootRec(rec) {

}

AzFieldList::AzFieldList(const AzFieldList & src):QObject(0) {
    copy(src);
}

AzFieldList& AzFieldList::operator = (const AzFieldList& src) {
    if (this == &src)
        return *this;
    checkIsCanChange();
    copy(src);
    return *this;
}

void AzFieldList::copy(const AzFieldList& src) {
    mFields = src.mFields;
}



AzFieldList::~AzFieldList() {
    clear();
}


/*!
 * \brief release all resources
*/


void AzFieldList::clear() {
    checkIsCanChange();
    mFields.clear();
}

/*!
	Добавляем к списку полей
    \Warning Не реализовано проверка на одинаковые поля.
*/
void AzFieldList::append(const QString& name, const AzField& src) {
    checkIsCanChange();
    mFields.append(src);
    mFields.last().mName = name;
    emit fieldChanged(AzFieldList::OnInserted,mFields.size() - 1);
}

/*!
	Поиск позиции поля по имени
    \Note - чуствительно к регистру
*/
int AzFieldList::indexOf(const QString& name) {
    for (int i = 0; i < mFields.size(); ++i) {
        if (mFields[i].mName == name)
			return i;
	}
	return -1;
}

bool AzFieldList::isNameExist(const QString& name) {
	return indexOf(name) == -1;
}



/*!
 * \brief AzFieldList::checkIsCanChange
 * If record is has a value raise  exception
 * \sa AzRecordDataSource.isOpen()
 */
void AzFieldList::checkIsCanChange() const {
    if (mRootRec && mRootRec->childCount() > 0)
        throw AzFieldException(AzFieldException::CannotChangeFieldError);
}

/*!
 * \brief AzFieldList::fieldsType
 * \return Пустые AzRecordValues с типом данных.
 */
AzRecordValues AzFieldList::fieldsType() const {
    AzRecordValues res(mFields.size());
    for (int i = 0; i < mFields.size();++i) {
        res[i] = mFields[i].type();
    }
    return res;
}
